/*
 * Albareth - an action roleplaying game.
 * Copyright (C) 2008 Jens Anuth
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 *   02110-1301, USA.
 * 
 * $Id: WorldGenerator.java 46 2008-05-15 18:09:39Z jens464 $
*/
package albareth.generator;

import albareth.core.GameMap;
import albareth.core.LevelSpawnConfiguration;
import albareth.core.World;
import albareth.core.entity.Ground;
import albareth.core.entity.Item;
import albareth.core.entity.ItemFactory;
import albareth.core.entity.item.Teleporter;
import albareth.frontend.TileCollection;
import albareth.util.Location;
import frosch.util.Range;
import frosch.util.WeightedSet;

public class WorldGenerator
{
    private int _dungeonLevels;
    
    private LevelSpawnConfiguration[] _levelSpawnConfig;
    
    private MapGenerator _angbandGen = new AngbandDungeonGenerator(8, 8);
    /** Default maze generator, but with shuffled ground tiles. */
    private MapGenerator _mazeGen = new MazeGenerator(2, 1.0)
    {
        public void generateMap(int width, int height)
        {
            super.generateMap(width, height);
            
            //beautify architecture:
            //randomize wall- and floor-tiles:
            WeightedSet floors =
                new WeightedSet().add(Ground.FLOOR_DARK1, 1)
                .add(Ground.FLOOR_DARK2, 2).add(Ground.FLOOR_DARK3, 3)
                .add(Ground.FLOOR_LIGHT1, 10).add(Ground.FLOOR_LIGHT2, 6)
                .add(Ground.FLOOR_LIGHT3, 1);
            WeightedSet walls = 
                new WeightedSet().add(Ground.WALL1, 1).add(Ground.WALL2, 10);

            for (int x = 0; x < map.getWidth(); x++)
            {
                for (int y = 0; y < map.getWidth(); y++)
                {
                    if (map.getGround(x, y) == DEFAULT_FLOOR) {
                        map.setGround((Ground)floors.randomElement(), x, y);
                    } else if (map.getGround(x, y) == DEFAULT_WALL) {
                        map.setGround((Ground)walls.randomElement(), x, y);
                    }
                }
            }
        }
    };

    
    
    public WorldGenerator()
    {
        _levelSpawnConfig = new LevelSpawnConfiguration[20];
        
        _levelSpawnConfig[0] = new LevelSpawnConfiguration(1, .5, new Range(1, 1));
        _levelSpawnConfig[1] = new LevelSpawnConfiguration(2, .5, new Range(1, 2));
        _levelSpawnConfig[2] = new LevelSpawnConfiguration(3, .5, new Range(1, 3));
        _levelSpawnConfig[3] = new LevelSpawnConfiguration(4, .5, new Range(2, 4));
        _levelSpawnConfig[3].setBossLevel(true);

        _levelSpawnConfig[4] = new LevelSpawnConfiguration(5, .75, new Range(2, 5));
        _levelSpawnConfig[5] = new LevelSpawnConfiguration(6, .75, new Range(3, 6));
        _levelSpawnConfig[6] = new LevelSpawnConfiguration(7, .75, new Range(4, 7));
        _levelSpawnConfig[7] = new LevelSpawnConfiguration(8, .75, new Range(4, 8));
        _levelSpawnConfig[7].setBossLevel(true);

        _levelSpawnConfig[8] = new LevelSpawnConfiguration(9, 1.0, new Range(5, 9));
        _levelSpawnConfig[9] = new LevelSpawnConfiguration(10, 1.0, new Range(6, 10));
        _levelSpawnConfig[10] = new LevelSpawnConfiguration(11, 1.0, new Range(6, 11));
        _levelSpawnConfig[11] = new LevelSpawnConfiguration(12, 1.0, new Range(7, 12));
        _levelSpawnConfig[11].setBossLevel(true);

        _levelSpawnConfig[12] = new LevelSpawnConfiguration(13, 1.25, new Range(8, 12));
        _levelSpawnConfig[13] = new LevelSpawnConfiguration(14, 1.25, new Range(9, 14));
        _levelSpawnConfig[14] = new LevelSpawnConfiguration(15, 1.25, new Range(9, 15));
        _levelSpawnConfig[15] = new LevelSpawnConfiguration(16, 1.25, new Range(10, 16));
        _levelSpawnConfig[15].setBossLevel(true);

        _levelSpawnConfig[16] = new LevelSpawnConfiguration(17, 1.5, new Range(11, 17));
        _levelSpawnConfig[17] = new LevelSpawnConfiguration(18, 1.5, new Range(12, 18));
        _levelSpawnConfig[18] = new LevelSpawnConfiguration(19, 1.5, new Range(13, 19));
        _levelSpawnConfig[19] = new LevelSpawnConfiguration(20, 1.75, new Range(16, 20));
        _levelSpawnConfig[19].setBossLevel(true);

        
        _dungeonLevels = _levelSpawnConfig.length;
            
            
    }
    
    
    
    
    public World generateWorld()
    {
        World world = new World();
        

        MapGenerator townGen = new TownMapGenerator(10);
        GameMap townMap = townGen.generate(128, 64, null);
        townMap.setName("The Village");
        world.addMap(townMap);

        //world.setBaseMap(townMap);


        GameMap previousMap = townMap;
        
        for (int i = 0; i < _dungeonLevels; i++)
        {
            //System.err.println("generate level");
            //GameMap map = _mazeGen.generate(32, 32, _levelSpawnConfig[i]);
            GameMap map = _angbandGen.generate(32, 32, _levelSpawnConfig[i]);
            map.setName("Dungeon Level " + (i + 1));

            world.addMap(map);
            if (i == 0) { //can adjust starting level here.
                world.setBaseMap(map);
            }

            connectMaps(previousMap, map);
            previousMap = map;
        }
        
        //testmonster:
        //NPCFactory npcFactory = new NPCFactory();
        //for (int i = 0; i < 15; i++)
        //{
            //NPC zombie = npcFactory.createMobile("zombie");
            //zombie.moveTo(dungeonMap.getRandomLocation());
        //}
        
        
        return world;
    }

    private void connectMaps(GameMap mapFrom, GameMap mapTo)
    {
        Location mapFromExit = mapFrom.getExitLocation();
        Location mapToEntr = mapTo.getEntranceLocation();

        //downstairs on source map:
        Item stairsDown = new Teleporter(
                "Stairs to " + mapTo.getName(), TileCollection.STAIRS_DOWN,
                mapToEntr, false
        );
        stairsDown.moveTo(mapFromExit);
        
        //upstairs on destination map:
        Item stairsUp = new Teleporter(
                "Stairs to " + mapFrom.getName(), TileCollection.STAIRS_UP,
                mapFromExit, false
        );
        stairsUp.moveTo(mapToEntr);
    }

}
